﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace LongNet.Util
{
    /// <summary>
    /// This class contains the datas and other informations of a pager. 
    /// </summary>
    /// <typeparam name="T">The type of data to contain.</typeparam>
    [Serializable]
    public class PaginatedList<T> : List<T>
    {
        #region Constructors

        /// <summary>
        /// Initializes an instance of <see cref="T:PaginatedList`1"/> with all data 
        /// to auto paginate and takes only the data that in current page index.
        /// </summary>
        /// <param name="source">All data to paginate.</param>
        /// <param name="pageSize">The size of page.</param>
        /// <param name="pageIndex">The index of page.</param>
        public PaginatedList(IEnumerable<T> source, int pageSize, int pageIndex)
        {
            source.ThrowsIfNull("source");

            this.InitializeProperties(source.Count(), pageSize, pageIndex);
            this.AddRange(source.Skip((PageIndex - 1) * PageSize).Take(PageSize));
        }

        /// <summary>
        /// Initializes an instance of <see cref="T:PaginatedList`1"/> with only the 
        /// data that in current page index.
        /// </summary>
        /// <param name="source">The data that in current page index.</param>
        /// <param name="recordCount">The record count of all data.</param>
        /// <param name="pageSize">The size of page.</param>
        /// <param name="pageIndex">The index of page.</param>
        public PaginatedList(IEnumerable<T> source, int recordCount, int pageSize, int pageIndex)
        {
            source.ThrowsIfNull("source");

            this.InitializeProperties(recordCount, pageSize, pageIndex);
            this.AddRange(source);
        }

        private void InitializeProperties(int recordCount, int pageSize, int pageIndex)
        {
            if (recordCount < 0)
                throw new ArgumentOutOfRangeException("recordCount", "The recordCount must greater than -1.");
            if (pageSize < 1)
                throw new ArgumentOutOfRangeException("pageSize", "The pageSize must greater than 0.");
            if (pageIndex < 1)
                throw new ArgumentOutOfRangeException("pageIndex", "The pageIndex must greater than 0.");

            PageSize = pageSize;
            PageIndex = pageIndex;
            RecordCount = recordCount;

            PageCount = (int)System.Math.Ceiling(RecordCount / (double)PageSize);

            if (PageIndex > PageCount)
                PageIndex = PageCount;
        }

        #endregion

        #region Properties

        /// <summary>
        /// 
        /// </summary>
        public int PageSize
        {
            get;
            private set;
        }

        /// <summary>
        /// 
        /// </summary>
        public int PageIndex
        {
            get;
            private set;
        }

        /// <summary>
        /// 
        /// </summary>
        public int RecordCount
        {
            get;
            private set;
        }

        /// <summary>
        /// 
        /// </summary>
        public int PageCount
        {
            get;
            private set;
        }


        /// <summary>
        /// 
        /// </summary>
        public bool IsEmpty
        {
            get
            {
                return (this.Count == 0);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        public bool IsFirstPage
        {
            get
            {
                return (PageIndex == 1);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        public bool IsMiddlePage
        {
            get
            {
                return (PageIndex > 1 && PageIndex < PageCount);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        public bool IsLastPage
        {
            get
            {
                return (PageIndex == PageCount);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        public bool HasNextPage
        {
            get
            {
                return (PageCount > 0 && PageIndex < PageCount);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        public bool HasPreviousPage
        {
            get
            {
                return (PageCount > 0 && PageIndex > 0);
            }
        }

        #endregion
    }
}
